/**
 * MIT License
 * 
 * Copyright (c) 2017 CaiDongyu
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package com.tunnel.server.http;
  
import java.io.ByteArrayOutputStream;

import com.tunnel.common.http.HttpPack;
import com.tunnel.common.tcp.TcpBaseHandler;
import com.tunnel.common.tunnel.TunnelDataSenderManager;
import com.tunnel.common.util.HttpUtil;
import com.tunnel.common.util.StringUtil;
import com.tunnel.server.http.HttpClientManager.HttpClient;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.util.Attribute;
import io.netty.util.AttributeKey;  
  
public class HttpServerHandler extends TcpBaseHandler{  
	public static final AttributeKey<String> HTTP_REQUESTID_KEY = AttributeKey.valueOf("http.requestId"); 
    ByteArrayOutputStream baos = null;
    
	public HttpServerHandler() {
		super("Http-Server");
	}

    
	@Override
	protected void channelRead0(ChannelHandlerContext ctx, ByteBuf buf) throws Exception {
		
		byte[] data = new byte[buf.readableBytes()];
		buf.getBytes(buf.readerIndex(), data);
	
		//数据中可能包含多个数据包
		//每个数据包都以结束符作为结束
		if(baos != null){
			baos.write(data, 0, data.length);
			data = baos.toByteArray();
		}
		HttpPack httpPack = HttpUtil.analyzeHttpData(data);
		boolean checkBodyIsOk = HttpUtil.checkBodyIsOk(httpPack, data);
//		LogUtil.d("Http Data: "+new String(data));
		if(httpPack == null || checkBodyIsOk == false){
//			LogUtil.d("waite for body");
			//说明还没有接收完，继续接收
			if(baos == null){
				baos = new ByteArrayOutputStream();
				baos.write(data, 0, data.length);
			}
		}else{
			//释放缓冲
			try {
				if(baos != null){
					baos.close();
					baos = null;
				}
			} catch (Exception e) {}
			
			String host = HttpUtil.getHost(httpPack.getHeader());
			host = host==null?"":host.trim();
//			LogUtil.d("host:"+host);
			
			HttpClient tunnelClient = HttpClientManager.get(host);
			if(tunnelClient != null){
				ChannelHandlerContext tunnelCtx = tunnelClient.getChannelHandlerContext();
				Attribute<String> attr = ctx.attr(HTTP_REQUESTID_KEY);
				if(attr.get() == null){//同一个http连接下，对requestId只设置一次
					//前16个字符是
					//requestId 时间戳+三位随机数，代表http请求的编号 占16位
					String requestId = System.currentTimeMillis()+StringUtil.getRandomString(3);
					boolean addSuccess = HttpChannelManager.add(host,requestId, ctx);
					while(!addSuccess){
						requestId = System.currentTimeMillis()+StringUtil.getRandomString(3);
						addSuccess = HttpChannelManager.add(host,requestId, ctx);
					}
					attr.setIfAbsent(requestId);
				}
				super.channelActive(ctx);
				if(attr.get() != null){
					byte hostIndexByte = (byte)(tunnelClient.getHostIndex());//只占一个字节，所以必须保证客端不能申请超过一个字节最大正数寻址范围
//					LogUtil.d("hi:"+hostIndexByte);
					byte[] requestIdBytes = attr.get().getBytes();
		        	TunnelDataSenderManager.commitData(TunnelDataSenderManager.HTTP_DATA_MSG, tunnelCtx, new byte[]{hostIndexByte},requestIdBytes,data);
				}
				
			}else{
				byte[] response404 = HttpUtil.response404("tunnel-server");
				ctx.writeAndFlush(response404).addListener(ChannelFutureListener.CLOSE);
			}
		}
	}
	

    @Override  
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
//        LogUtil.d("Http-Server exception");
        ctx.close();
    }
	

	@Override
    protected void handleWriterIdle(ChannelHandlerContext ctx) {
//        LogUtil.d("Http-Server timeout");
        super.handleReaderIdle(ctx);
        ctx.close();
    }
    
    
	@Override
	public void channelInactive(ChannelHandlerContext ctx) throws Exception {
//        LogUtil.d("Http-Server closing");
		super.channelInactive(ctx);
		Attribute<String> attr = ctx.attr(HTTP_REQUESTID_KEY);
        if(attr.get() != null){
        	String requestId = attr.get();
        	HttpChannelManager.remove(requestId);
        }
//        LogUtil.d("Http-Server close success");
	}
	
}  